// SPDX-License-Identifier: GPL-2.0-only
/*
 * ionapp_export.c
 *
 * It is a user space utility to create and export android
 * ion memory buffer fd to another process using unix domain socket as IPC.
 * This acts like a server for ionapp_import(client).
 * So, this server has to be started first before the client.
 *
 * Copyright (C) 2017 Pintu Kumar <pintu.ping@gmail.com>
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/time.h>
#include "ionutils.h"
#include "ipcsocket.h"
#include "ipckernel.h"

struct ion_buffer_info ion_bufs[DMA_BUFS_MAX_NUM] = {0};
wmark_dev_ioctl_t send_fds_mgs;

void print_usage(int argc, char *argv[])
{
	printf("Usage: %s [-h <help>] [-i <heap id>] [-s <size in bytes>]\n",
		argv[0]);
}

void full_send_msg_fd(struct ion_buffer_info *ion_bufs, wmark_dev_ioctl_t *mgs)
{
	int i = -1;
	for ( i = 0; i < DMA_BUFS_MAX_NUM; i++)
	{
		mgs->fds[i].fd = ion_bufs[i].buffd;
		mgs->fds[i].index = i;
		printf("Client fd = %d index = %d\n", mgs->fds[i].fd, i);
	}
	mgs->buf_len = ion_bufs[0].heap_size;
	printf("%s buf_len=%d\n", __func__, mgs->buf_len);
}
void init_full_ion_bufs(struct ion_buffer_info *ion_bufs, unsigned int heap_type, unsigned int heap_size, unsigned long flag_type)
{
	int i = -1;
	for ( i = 0; i < DMA_BUFS_MAX_NUM; i++)
	{
		ion_bufs[i].heap_size = heap_size;
		ion_bufs[i].heap_type = heap_type;
		ion_bufs[i].flag_type = flag_type;
	}
}


int main(int argc, char *argv[])
{
	int opt, ret, status, heapid;
	int sockfd, client_fd, shared_fd;
	unsigned char *map_buf;
	unsigned long map_len, heap_type, heap_size, flags;
	ipc_dev_info_t ipc_dev;

	if (argc < 2) {
		print_usage(argc, argv);
		return -1;
	}

	heap_size = 0;
	flags = 0;
	heap_type = ION_HEAP_TYPE_SYSTEM;

	while ((opt = getopt(argc, argv, "hi:s:")) != -1) {
		switch (opt) {
		case 'h':
			print_usage(argc, argv);
			exit(0);
			break;
		case 'i':
			heapid = atoi(optarg);
			printf("--- %s %s %d heapid=%d\n", __FILE__, __FUNCTION__, __LINE__, heapid);
			switch (heapid) {
			case 0:
				heap_type = ION_HEAP_TYPE_SYSTEM;
				break;
			case 1:
				heap_type = ION_HEAP_TYPE_SYSTEM_CONTIG;
				break;
			case 2:
				heap_type = ION_HEAP_TYPE_CARVEOUT;
				break;
			default:
				printf("ERROR: heap type not supported\n");
				exit(1);
			}
			break;
		case 's':
			heap_size = atoi(optarg);
			break;
		default:
			print_usage(argc, argv);
			exit(1);
			break;
		}
	}

	if (heap_size <= 0) {
		printf("heap_size cannot be 0\n");
		print_usage(argc, argv);
		exit(1);
	}

	printf("heap_type: %ld, heap_size: %ld\n", heap_type, heap_size);
	init_full_ion_bufs(ion_bufs, heap_type, heap_size, flags);

	/* This is server: open the socket connection first */
	/* Here; 1 indicates server or exporter */
	status = open_ipc_dev(&ipc_dev);
	if (status < 0) {
		fprintf(stderr, "<%s>: Failed opensocket.\n", __func__);
		goto err_ipc_dev;
	}

	ret = ion_export_buffer_fds(ion_bufs);
	if (ret < 0) {
		fprintf(stderr, "FAILED: ion_get_buffer_fd\n");
		goto err_export;
	}

	full_send_msg_fd(ion_bufs, &send_fds_mgs);
	ret = dev_send_fds(&ipc_dev, &send_fds_mgs);
	if (ret < 0) {
		fprintf(stderr, "FAILED: socket_send_fd\n");
		goto err_send;
	}

	while (1)
	{
		read_all_bufs(ion_bufs);
		// write_all_bufs(ion_bufs, "oooooooooooooooooooooooo");
		write_buffer_str(ion_bufs[0].buffer, ion_bufs[0].buflen,"aaaaaaaaaaaaaaaaaaa");
		write_buffer_str(ion_bufs[1].buffer, ion_bufs[1].buflen,"bbbbbbbbbbbbbbbbbbb");
		write_buffer_str(ion_bufs[2].buffer, ion_bufs[2].buflen,"ccccccccccccccccccc");
		write_buffer_str(ion_bufs[3].buffer, ion_bufs[3].buflen,"ddddddddddddddddddd");
		usleep(10000);
	}
	

err_send:
err_export:
	// ion_close_buffer_fd(&info);

err_ipc_dev:
	close_ipc_dev(&ipc_dev);

	return 0;
}
